import 'dart:async';

import 'package:flutter/material.dart';

class AnimatedTweenBuilderPage extends StatefulWidget {
  const AnimatedTweenBuilderPage({Key? key}) : super(key: key);

  @override
  State<AnimatedTweenBuilderPage> createState() =>
      _AnimatedTweenBuilderPageState();
}

class _AnimatedTweenBuilderPageState extends State<AnimatedTweenBuilderPage> {
  int value = 2023;
  Timer? _timer;

  _startTimer() {
    _cancelTimer();
    _timer ??= Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        value--;
      });
    });
  }

  _cancelTimer() {
    if (_timer != null) {
      _timer!.cancel();
      _timer = null;
    }
  }

  @override
  void dispose() {
    _cancelTimer();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AnimatedTweenBuilder'),
      ),
      body: Center(
        child: Column(children: [
          AnimatedFlipCounter(
            value: value,
            duration: const Duration(milliseconds: 100),
            size: 50,
          ),
          ElevatedButton(onPressed: _startTimer, child: const Text("Start")),
          ElevatedButton(onPressed: _cancelTimer, child: const Text("Cancel"))
        ]),
      ),
    );
  }
}

class AnimatedFlipCounter extends StatelessWidget {
  final int value;
  final Duration duration;
  final double size;
  final Color textColor;
  const AnimatedFlipCounter(
      {Key? key,
      required this.value,
      required this.duration,
      this.size = 100,
      this.textColor = Colors.black})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<int> digits = value == 0 ? [0] : [];
    int v = value;
    if (v < 0) {
      v *= -1;
    }
    while (v > 0) {
      digits.add(v);
      v = v ~/ 10;
    }

    return Row(
      mainAxisSize: MainAxisSize.min,
      children: List.generate(digits.length, (int i) {
        return SingleDigitFlipCounter(
            key: ValueKey(digits.length - i),
            value: digits[digits.length - i - 1].toDouble(),
            duration: duration,
            height: size,
            width: size / 1.8,
            color: textColor);
      }),
    );
  }
}

class SingleDigitFlipCounter extends StatelessWidget {
  final double value;
  final Duration duration;
  final double height;
  final double width;
  final Color color;

  const SingleDigitFlipCounter(
      {Key? key,
      required this.value,
      required this.duration,
      required this.height,
      required this.width,
      required this.color})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TweenAnimationBuilder(
        tween: Tween(begin: value, end: value),
        duration: duration,
        builder: (context, double value, child) {
          final whole = value ~/ 1;
          final decimal = value - whole;
          return SizedBox(
            height: height,
            width: width,
            child: Stack(
              children: [
                _buildSingleDigit(
                    digit: whole % 10,
                    offset: height * decimal,
                    opacity: 1 - decimal),
                _buildSingleDigit(
                    digit: (whole + 1) % 10,
                    offset: height * decimal - height,
                    opacity: decimal)
              ],
            ),
          );
        });
  }

  Widget _buildSingleDigit(
      {required int digit, required double offset, required double opacity}) {
    return Positioned(
      bottom: offset,
      child: Text(
        "$digit",
        style: TextStyle(fontSize: height, color: color.withOpacity(opacity)),
      ),
    );
  }
}
